package org.jpro.datasource;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.alibaba.druid.pool.xa.DruidXADataSource;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * <P>功能描述 : 数据源 </P>
 * <P>File name : AbstractDatasource </P>
 * <P>Author : 王泽浩 </P>
 * <P>E-Mail : 1028625100@qq.com </P>
 * <P>Date : 2017/3/1 下午4:10</P>
 */
@Slf4j
@Getter
@Setter
public abstract class AbstractDatasource {

    /**
     * 连接数据库的url
     */
    protected String url;

    /**
     * 连接数据库的用户名
     */
    protected String username;

    /**
     * 连接数据库的密码
     */
    protected String password;

    /**
     * 根据url自动识别
     */
    protected String driverClassName;

    /**
     * 初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时 默认设置3个
     */
    protected int initialSize = 10;

    /**
     * 最小连接池数量
     */
    protected int minIdle = 5;

    /**
     * 最大连接池数量
     */
    protected int maxActive = 50;

    /**
     * 获取连接时最大等待时间，单位毫秒。配置了maxWait之后，缺省启用公平锁，并发效率会有所下降，如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
     */
    protected int maxWait;

    /**
     * 有两个含义：
     * 1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据，详细看testWhileIdle属性的说明
     */
    protected int timeBetweenEvictionRunsMillis = 30000;

    protected int minEvictableIdleTimeMillis = 30000;

    /**
     * 验证连接有效与否的SQL，不同的数据配置不同
     */
    protected String validationQuery;

    /**
     * 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。
     */
    protected boolean testWhileIdle = true;

    /**
     * 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。
     */
    protected boolean testOnBorrow;

    /**
     * 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能
     */
    protected boolean testOnReturn;

    /**
     * 是否缓存preparedStatement，也就是PSCache。PSCache对支持游标的数据库性能提升巨大，比如说oracle。在mysql下建议关闭。
     */
    protected boolean poolPreparedStatements;

    protected int maxPoolPreparedStatementPerConnectionSize = 20;

    /**
     * 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：
     * 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
     */
    protected String filters = "stat,wall,log4j";

    protected String connectionProperties;

    private DruidXADataSource datasource;

    public synchronized DataSource dataSource() {

        if (datasource != null) {
            return this.datasource;
        }

        datasource = new DruidXADataSource();
        datasource.setUrl(this.url);
        datasource.setUsername(this.username);
        datasource.setPassword(this.password);
        datasource.setDriverClassName(this.driverClassName);
        datasource.setInitialSize(this.initialSize);
        datasource.setMinIdle(this.minIdle);
        datasource.setMaxActive(this.maxActive);
        datasource.setMaxWait(this.maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(this.timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(this.minEvictableIdleTimeMillis);
        datasource.setValidationQuery(this.validationQuery);
        datasource.setTestWhileIdle(this.testWhileIdle);
        datasource.setTestOnBorrow(this.testOnBorrow);
        datasource.setTestOnReturn(this.testOnReturn);
        datasource.setPoolPreparedStatements(this.poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(this.maxPoolPreparedStatementPerConnectionSize);
        try {
            datasource.setFilters(this.filters);
        } catch (SQLException e) {
            log.error("druid configuration initialization filter", e);
        }
        datasource.setConnectionProperties(this.connectionProperties);
        return datasource;
    }
}
